package lumis.content.core;

import java.io.Serializable;
import java.util.Locale;

import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

import lumis.portal.manager.ManagerFactory;

import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.annotations.GenericGenerator;

/**
 * A tag object entity. Represents a tag entry and an association between tag and its content version.
 * This element must be a {@link Content}.
 * 
 * <p>
 * <b>Note:</b> This entity is not considered stable for use in queries.
 * 
 * @stereotype entity
 * 
 * @version $Revision: 13092 $ $Date: 2011-05-28 18:19:06 -0300 (Sat, 28 May 2011) $
 * @since 6.0.0
 */
@SuppressWarnings("serial")
@Entity
@Table(name="lum_ContentTag")
@GenericGenerator(name="portal-guid", strategy="lumis.portal.dao.hibernate.GuidGenerator")
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class ContentTag implements Serializable
{
	/**
	 * String used to split a string of list of tags. Its a reserved word. 
	 * @since 6.0.0
	 */
	public final static String TAG_STRING_SEPARATOR = ",";
	
	/**
	 * The tag content source id.
	 * @since 6.0.0
	 */
	final static String SOURCE_ID = "tag";
	
	/**
	 * The maximum length for a tag name.
	 * @since 6.0.0
	 */
	final static int TAG_MAX_LENGTH = 30;
	
	@Id @GeneratedValue(generator="portal-guid")
	private String id;
	
	private String name;
	
	private String normalizedName;

	@ManyToOne(fetch=FetchType.LAZY)
	@JoinColumn(name="id", referencedColumnName="itemId", insertable=false, updatable=false)
	private ContentVersion contentVersion;
	
	/**
	 * The {@link ContentTag} constructor.
	 * 
	 * @since 6.0.0
	 */
	ContentTag() 
	{
	}
	
	/**
	 * Returns the tag identifier.
	 * 
	 * @return id, the tag identifier.
	 * @since 6.0.0
	 */
	public String getId()
	{
		return id;
	}

	/**
	 * Returns the tag name, as it was persisted at first time.
	 * 
	 * @return name, the tag name.
	 * @since 6.0.0
	 */
	public String getName() 
	{
		return name;
	}

	/**
	 * Sets the tag name.
	 * <p>
	 * If the tag name is null, or its length be smaller than zero or bigger than 30 a {@link IllegalArgumentException} is shown.
	 * 
	 * @param name, the tag name.
	 * @since 6.0.0
	 */
	void setName(String name) 
	{
		if(name == null || name.length() == 0)
			throw new IllegalArgumentException("Name length must be bigger than zero!");
		
		if(name.length() > TAG_MAX_LENGTH)
			throw new IllegalArgumentException("Name length max size is "+TAG_MAX_LENGTH+".");
		
		if(name.contains(TAG_STRING_SEPARATOR))
			throw new IllegalArgumentException("Name can not contain "+TAG_STRING_SEPARATOR+".");
		
		if(!ContentUtil.isValidTagName(name))
			throw new IllegalArgumentException("Name can not contain '{'.");
		
		this.name = name;
		this.normalizedName = ContentUtil.normalizeTagName(name);
	}

	/**
	 * The tag name in upper case, used to do comparisons.
	 * <p>
	 * To do the conversion the locale {@link Locale#ENGLISH} is used as parameter for {@link String#toUpperCase(Locale)}.
	 * 
	 * @return The tag name in upper case.
	 * @since 6.0.0
	 */
	String getNormalizedName() 
	{
		return normalizedName;
	}

	/**
	 * The {@link ContentVersion} of this tag.
	 * 
	 * @return the content version.
	 * @since 6.0.0
	 */
	public ContentVersion getContentVersion() 
	{
		return contentVersion;
	}
	
	/**
	 * Sets the {@link ContentVersion} for this {@link ContentTag}.
	 * 
	 * @param contentVersion
	 * @since 6.0.0
	 */
	void setContentVersion(ContentVersion contentVersion)
	{
		this.contentVersion = contentVersion;
	}
	
	/**
	 * Deletes a tag entry.
	 * <p>
	 * It implies in deleting the {@link ContentTag}, {@link Content} 
	 * element and all associations with these elements.
	 * 
	 * @see IContentManager#deleteContent(Content)
	 * @since 6.0.0
	 */
	public void deleteContent()
	{
		// deletes the content
		Content content = getContentVersion().getContentLocale().getContent();
		ManagerFactory.getEntityManager().remove(content);
		
		// deletes the entity contentTag
		ManagerFactory.getEntityManager().remove(this);
	}
}
